Predicting Data Science Salaries
Anh Nguyen, Amira Bendjama, Hong Doan
Introduction and Problem Statement
The field of data science has experienced remarkable growth in recent
years, with organizations across diverse industries recognizing the
value of data-driven decision making. According to an article by 365
Data Science, the US Bureau of Labor Statistics estimated that the
employment rate for data scientists will grow by 36% from 2021 to 2031.
This rate is significantly higher than the average growth rate of 5%,
indicating substantial growth and demand for data science talent. The
surging demand for data science presents both opportunities and
challenges for job seekers, particularly recent graduates. One of the
significant hurdles they face is the lack of salary transparency in the
data science job market. This opacity creates uncertainty regarding
compensation and hinders job seekers’ ability to negotiate fair
salaries.
There are significant variations in data science salaries across
different industries and locations. For instance, according to Zippia,
data scientists working in the finance and technology sectors tend to
earn higher salaries compared to those in other industries. Similarly,
the geographical location also plays a crucial role in determining
salaries. Large cities with higher concentration of tech companies and
living costs such as San Francisco and New York offer higher salaries
than smaller cities.
The discrepancies in data science salaries can also be attributed to
various factors, including job responsibilities, experience level,
educational background, and specific skill sets. A study conducted by
Burtch Works, a leading executive recruiting firm, found that data
scientists with advanced degrees, such as Ph.D., tend to command higher
salaries compared to those with bachelor’s or master’s degrees.
Similarly, professionals with expertise in specialized areas, such as
machine learning or natural language processing, often earn higher
salaries due to the high demand for these skills.
According to a report surveyed 1,000 US-based full-time employees,
conducted by Visier, 79% of all survey respondents want some form of pay
transparency and 32% want total transparency, in which all employee
salaries are publicized. However, the 2022 Pay Clarity Survey by WTW
found that only 17% of companies are disclosing pay range information in
U.S. locations where not required by state or local laws. For the states
that have pay transparency laws such as Colorado and New York, there has
been a decline in job postings since the law went into effect. Some
employers comply with the new laws by expanding the salary ranges,
sometimes to ridiculous lengths. These statistics highlight the lack of
pay transparency not only in the field of data science, but across
multiple job markets. Job seekers often struggle to estimate salaries
for data science positions due to the scarcity of reliable
information.
To address this problem, our project aims to develop a predictive
model that estimates the salary for data science jobs. By leveraging
publicly available data and employing machine learning algorithms, we
seek to provide job seekers a better understanding of salary
expectations within the data science job market and empower them to
negotiate fair and competitive compensation packages.
Data Sources and Data preparation
install.packages("rpart.plot")
Installing package into ‘C:/Users/mira/AppData/Local/R/win-library/4.3’
(as ‘lib’ is unspecified)
trying URL 'https://cran.rstudio.com/bin/windows/contrib/4.3/rpart.plot_3.1.1.zip'
Content type 'application/zip' length 1034594 bytes (1010 KB)
downloaded 1010 KB
package ‘rpart.plot’ successfully unpacked and MD5 sums checked
The downloaded binary packages are in
C:\Users\mira\AppData\Local\Temp\RtmpkPyMFF\downloaded_packages
install.packages("ggplot2")
Error in install.packages : Updating loaded packages
install.packages("e1071")
Error in install.packages : Updating loaded packages
# Install the plotly package
install.packages("plotly")
Installing package into ‘C:/Users/mira/AppData/Local/R/win-library/4.3’
(as ‘lib’ is unspecified)
trying URL 'https://cran.rstudio.com/bin/windows/contrib/4.3/plotly_4.10.1.zip'
Content type 'application/zip' length 3241461 bytes (3.1 MB)
downloaded 3.1 MB
package ‘plotly’ successfully unpacked and MD5 sums checked
Restarting R session...
library(ggplot2)
ds_salaries <- read.csv("ds_salaries.csv")
summary(ds_salaries)
X work_year experience_level employment_type job_title
Min. : 0.0 Min. :2020 Length:607 Length:607 Length:607
1st Qu.:151.5 1st Qu.:2021 Class :character Class :character Class :character
Median :303.0 Median :2022 Mode :character Mode :character Mode :character
Mean :303.0 Mean :2021
3rd Qu.:454.5 3rd Qu.:2022
Max. :606.0 Max. :2022
salary salary_currency salary_in_usd employee_residence
Min. : 4000 Length:607 Min. : 2859 Length:607
1st Qu.: 70000 Class :character 1st Qu.: 62726 Class :character
Median : 115000 Mode :character Median :101570 Mode :character
Mean : 324000 Mean :112298
3rd Qu.: 165000 3rd Qu.:150000
Max. :30400000 Max. :600000
remote_ratio company_location company_size
Min. : 0.00 Length:607 Length:607
1st Qu.: 50.00 Class :character Class :character
Median :100.00 Mode :character Mode :character
Mean : 70.92
3rd Qu.:100.00
Max. :100.00
This dataset has 607 rows and 12 columns
We want to focus on “USD” currency so we keep the “salary_in_usd”
column and drop “salary_currency” and “salary” column by using
subset()
There are no null values
There are 42 duplicate rows
# Remove duplicate rows
df <- ds_salaries[!duplicated(ds_salaries), ]
# check again
repeated_entries_new <- subset(df, duplicated(df))
print(repeated_entries_new)
Salaries groups
Adding new column to split our salaries into three groups Low , High,
Medium.The approach is to use Percentiles by Dividing the dataset based
on them. Hence, we are classifying salaries below the 25th percentile as
“Low”, salaries between the 25th and 75th percentile as “Medium”, and
salaries above the 75th percentile as “High”.
# adding new column
# Calculate the percentiles
percentiles <- quantile(df$salary_in_usd, probs = c(0.25, 0.75))
# Define the thresholds
low_threshold <- percentiles[1] # 25th percentile
high_threshold <- percentiles[2] # 75th percentile
# Create a new column based on percentiles
df$salary_classification <- ifelse(df$salary_in_usd < low_threshold, "Low",
ifelse(df$salary_in_usd > high_threshold, "High", "Medium"))
- Data Exploration and Visualization
Top 10 Jobs in the dataset:
# Get top 10 job titles and their value counts
top10_job_title <- head(sort(table(df$job_title), decreasing = TRUE), 10)
top10_job_title_df <- data.frame(job_title = names(top10_job_title), count = as.numeric(top10_job_title))
top10_job_title_df
NA
# Load the required packages
library(plotly)
Registered S3 method overwritten by 'htmlwidgets':
method from
print.htmlwidget tools:rstudio
Attaching package: ‘plotly’
The following object is masked from ‘package:ggplot2’:
last_plot
The following object is masked from ‘package:stats’:
filter
The following object is masked from ‘package:graphics’:
layout
# Define custom color palette
custom_colors <- c("#FF6361", "#FFA600", "#FFD700", "#FF76BC", "#69D2E7", "#6A0572", "#FF34B3", "#118AB2", "#FFFF99", "#FFC1CC")
# Create bar plot
fig <- plot_ly(data = top10_job_title_df, x = ~reorder(job_title, -count), y = ~count, type = "bar",
marker = list(color = custom_colors), text = ~count) %>%
layout(title = "Top 10 Job Titles", xaxis = list(title = "Job Titles"), yaxis = list(title = "Count"),
font = list(size = 17), template = "plotly_dark")
# Adjust layout settings to avoid label overlap
fig <- fig %>% layout(
margin = list(b = 150), # Increase bottom margin to provide space for labels
xaxis = list(
tickangle = 45, # Rotate x-axis tick labels
automargin = TRUE # Automatically adjust margins to avoid overlap
)
)
# Display the plot
fig
NA
NA
Experience level categories:
Our Dataset has 4 different experience categories: - EN: Entry-level
/ Junior - MI: Mid-level / Intermediate - SE: Senior-level / Expert -
EX: Executive-level / Director
# Create a mapping of category abbreviations to full names
category_names_experience <- c("EN" = "Entry-level",
"MI" = "Mid-level",
"SE" = "Senior-level",
"EX" = "Executive-level")
# Get the sorted experience data
experience <- head(sort(table(df$experience_level), decreasing = TRUE))
# Replace the category names with full forms
names(experience) <- category_names_experience[names(experience)]
# Calculate the percentage for each category
percentages <- round(100 * experience / sum(experience), 2)
# Define a custom color palette
custom_colors <- c("#FFA998", "#FF76BC", "#69D2E7", "#FFA600")
# Create a pie chart with cute appearance
pie(experience, labels = paste(names(experience), "(", percentages, "%)"), col = custom_colors, border = "white", clockwise = TRUE, init.angle = 90)
# Add a legend with cute colors
legend("topright", legend = names(experience), fill = custom_colors, border = "white", cex = 0.8)
# Add a title with a cute font
title("Experience Distribution", font.main = 1)

Compnay size distribution
# Create a mapping of category abbreviations to full names
category_names_company <- c("M" = "Medium",
"L" = "Large",
"S" = "Small"
)
# Get the sorted company size data
company_size <- head(sort(table(df$company_size), decreasing = TRUE))
# Replace the category names with full forms
names(company_size) <- category_names_company[names(company_size)]
# Set the maximum value for the y-axis
max_count <- max(company_size)
# Create a bar plot with adjusted y-axis limits
barplot(company_size, col = custom_colors, main = "Company Size Distribution", xlab = "Company Size", ylab = "Count", ylim = c(0, max_count + 10))

NA
NA
Salaries Distribution
# Set the scipen option to a high value
options(scipen = 10)
# Create boxplot of salaries
bp <- boxplot(df$salary_in_usd / 1000,
col = "skyblue",
main = "Boxplot of Salaries",
ylab = "Salary in Thousands USD",
notch = TRUE)

Salaries classification Distribution
# Get the sorted salary classification data
salary_classification <- sort(table(df$salary_classification), decreasing = TRUE)
salary_classification_df <- data.frame(salary_classification= names(salary_classification ), count = as.numeric(salary_classification ))
fig <- plot_ly(
data = salary_classification_df,
x = ~reorder(salary_classification, -count),
y = ~count,
type = "bar",
marker = list(color = custom_colors),
text = ~count,
width = 700,
height = 400
)
fig <- fig %>% layout(
title = "Salary Classification Distribution",
xaxis = list(title = "Salary Classification"),
yaxis = list(title = "Count"),
font = list(size = 17),
template = "ggplot2"
)
fig
NA
NA
NA
# Create a data frame with counts of experience levels by salary classification
experience_salary <- table(df$experience_level, df$salary_classification)
# Define custom colors for each experience level
custom_colors <- c("#69D2E7", "#FFA600", "#FF6361", "#FFD700")
# Create a data frame for the plot
plot_data <- data.frame(Experience = rownames(experience_salary),
Salary_Classification = colnames(experience_salary),
Count = as.vector(experience_salary))
# Convert Count column to numeric
plot_data$Count <- as.numeric(plot_data$Count)
# Create the bar plot
library(plotly)
fig <- plot_ly(data = plot_data, x = ~Salary_Classification, y = ~Count,
color = ~Experience, colors = custom_colors, type = "bar") %>%
layout(title = "Experience Level by Salary Classification",
xaxis = list(title = "Salary Classification"),
yaxis = list(title = "Count"),
font = list(size = 17),
template = "plotly_dark")
fig
NA
NA
Modeling
a. Logestic Regression
b. Random Forest
c. Decision Tree
Evaluation and Results
a. Linear Regression
b. Random Forest
c. Decision Tree
Major Challenges and Solutions
Data is not updated
Data is imbalanced
Conclusion and Future Work
References
The
Data Scientist Job Outlook in 2023 | 365 Data Science
Which
Industry Pays the Highest Data Scientist Salary? How To Make The Most
Money As A Data Scientist - Zippia
Burtch-Works-Study_DS-PAP-2019.pdf
(burtchworks.com)
New
Visier Report Reveals 79% of Employees Want Pay Transparency
(prnewswire.com)
More
NA organizations plan to disclose pay information - WTW
(wtwco.com)
Study:
Pay Transparency Reduces Recruiting Costs (shrm.org)
LS0tDQp0aXRsZTogIkRhdGEgU2NpZW5jZSBTYWxhcmllcyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiMgUHJlZGljdGluZyBEYXRhIFNjaWVuY2UgU2FsYXJpZXMNCg0KKioqQW5oIE5ndXllbiwgQW1pcmEgQmVuZGphbWEsIEhvbmcgRG9hbioqKg0KDQoxLiAgKipJbnRyb2R1Y3Rpb24gYW5kIFByb2JsZW0gU3RhdGVtZW50KipcDQoNCiAgICBUaGUgZmllbGQgb2YgZGF0YSBzY2llbmNlIGhhcyBleHBlcmllbmNlZCByZW1hcmthYmxlIGdyb3d0aCBpbiByZWNlbnQgeWVhcnMsIHdpdGggb3JnYW5pemF0aW9ucyBhY3Jvc3MgZGl2ZXJzZSBpbmR1c3RyaWVzIHJlY29nbml6aW5nIHRoZSB2YWx1ZSBvZiBkYXRhLWRyaXZlbiBkZWNpc2lvbiBtYWtpbmcuIEFjY29yZGluZyB0byBhbiBhcnRpY2xlIGJ5IDM2NSBEYXRhIFNjaWVuY2UsIHRoZSBVUyBCdXJlYXUgb2YgTGFib3IgU3RhdGlzdGljcyBlc3RpbWF0ZWQgdGhhdCB0aGUgZW1wbG95bWVudCByYXRlIGZvciBkYXRhIHNjaWVudGlzdHMgd2lsbCBncm93IGJ5IDM2JSBmcm9tIDIwMjEgdG8gMjAzMS4gVGhpcyByYXRlIGlzIHNpZ25pZmljYW50bHkgaGlnaGVyIHRoYW4gdGhlIGF2ZXJhZ2UgZ3Jvd3RoIHJhdGUgb2YgNSUsIGluZGljYXRpbmcgc3Vic3RhbnRpYWwgZ3Jvd3RoIGFuZCBkZW1hbmQgZm9yIGRhdGEgc2NpZW5jZSB0YWxlbnQuIFRoZSBzdXJnaW5nIGRlbWFuZCBmb3IgZGF0YSBzY2llbmNlIHByZXNlbnRzIGJvdGggb3Bwb3J0dW5pdGllcyBhbmQgY2hhbGxlbmdlcyBmb3Igam9iIHNlZWtlcnMsIHBhcnRpY3VsYXJseSByZWNlbnQgZ3JhZHVhdGVzLiBPbmUgb2YgdGhlIHNpZ25pZmljYW50IGh1cmRsZXMgdGhleSBmYWNlIGlzIHRoZSBsYWNrIG9mIHNhbGFyeSB0cmFuc3BhcmVuY3kgaW4gdGhlIGRhdGEgc2NpZW5jZSBqb2IgbWFya2V0LiBUaGlzIG9wYWNpdHkgY3JlYXRlcyB1bmNlcnRhaW50eSByZWdhcmRpbmcgY29tcGVuc2F0aW9uIGFuZCBoaW5kZXJzIGpvYiBzZWVrZXJzJyBhYmlsaXR5IHRvIG5lZ290aWF0ZSBmYWlyIHNhbGFyaWVzLg0KDQogICAgVGhlcmUgYXJlIHNpZ25pZmljYW50IHZhcmlhdGlvbnMgaW4gZGF0YSBzY2llbmNlIHNhbGFyaWVzIGFjcm9zcyBkaWZmZXJlbnQgaW5kdXN0cmllcyBhbmQgbG9jYXRpb25zLiBGb3IgaW5zdGFuY2UsIGFjY29yZGluZyB0byBaaXBwaWEsIGRhdGEgc2NpZW50aXN0cyB3b3JraW5nIGluIHRoZSBmaW5hbmNlIGFuZCB0ZWNobm9sb2d5IHNlY3RvcnMgdGVuZCB0byBlYXJuIGhpZ2hlciBzYWxhcmllcyBjb21wYXJlZCB0byB0aG9zZSBpbiBvdGhlciBpbmR1c3RyaWVzLiBTaW1pbGFybHksIHRoZSBnZW9ncmFwaGljYWwgbG9jYXRpb24gYWxzbyBwbGF5cyBhIGNydWNpYWwgcm9sZSBpbiBkZXRlcm1pbmluZyBzYWxhcmllcy4gTGFyZ2UgY2l0aWVzIHdpdGggaGlnaGVyIGNvbmNlbnRyYXRpb24gb2YgdGVjaCBjb21wYW5pZXMgYW5kIGxpdmluZyBjb3N0cyBzdWNoIGFzIFNhbiBGcmFuY2lzY28gYW5kIE5ldyBZb3JrIG9mZmVyIGhpZ2hlciBzYWxhcmllcyB0aGFuIHNtYWxsZXIgY2l0aWVzLg0KDQogICAgVGhlIGRpc2NyZXBhbmNpZXMgaW4gZGF0YSBzY2llbmNlIHNhbGFyaWVzIGNhbiBhbHNvIGJlIGF0dHJpYnV0ZWQgdG8gdmFyaW91cyBmYWN0b3JzLCBpbmNsdWRpbmcgam9iIHJlc3BvbnNpYmlsaXRpZXMsIGV4cGVyaWVuY2UgbGV2ZWwsIGVkdWNhdGlvbmFsIGJhY2tncm91bmQsIGFuZCBzcGVjaWZpYyBza2lsbCBzZXRzLiBBIHN0dWR5IGNvbmR1Y3RlZCBieSBCdXJ0Y2ggV29ya3MsIGEgbGVhZGluZyBleGVjdXRpdmUgcmVjcnVpdGluZyBmaXJtLCBmb3VuZCB0aGF0IGRhdGEgc2NpZW50aXN0cyB3aXRoIGFkdmFuY2VkIGRlZ3JlZXMsIHN1Y2ggYXMgUGguRC4sIHRlbmQgdG8gY29tbWFuZCBoaWdoZXIgc2FsYXJpZXMgY29tcGFyZWQgdG8gdGhvc2Ugd2l0aCBiYWNoZWxvcidzIG9yIG1hc3RlcidzIGRlZ3JlZXMuIFNpbWlsYXJseSwgcHJvZmVzc2lvbmFscyB3aXRoIGV4cGVydGlzZSBpbiBzcGVjaWFsaXplZCBhcmVhcywgc3VjaCBhcyBtYWNoaW5lIGxlYXJuaW5nIG9yIG5hdHVyYWwgbGFuZ3VhZ2UgcHJvY2Vzc2luZywgb2Z0ZW4gZWFybiBoaWdoZXIgc2FsYXJpZXMgZHVlIHRvIHRoZSBoaWdoIGRlbWFuZCBmb3IgdGhlc2Ugc2tpbGxzLg0KDQogICAgQWNjb3JkaW5nIHRvIGEgcmVwb3J0IHN1cnZleWVkIDEsMDAwIFVTLWJhc2VkIGZ1bGwtdGltZSBlbXBsb3llZXMsIGNvbmR1Y3RlZCBieSBWaXNpZXIsIDc5JSBvZiBhbGwgc3VydmV5IHJlc3BvbmRlbnRzIHdhbnQgc29tZSBmb3JtIG9mIHBheSB0cmFuc3BhcmVuY3kgYW5kIDMyJSB3YW50IHRvdGFsIHRyYW5zcGFyZW5jeSwgaW4gd2hpY2ggYWxsIGVtcGxveWVlIHNhbGFyaWVzIGFyZSBwdWJsaWNpemVkLiBIb3dldmVyLCB0aGUgMjAyMiBQYXkgQ2xhcml0eSBTdXJ2ZXkgYnkgV1RXIGZvdW5kIHRoYXQgb25seSAxNyUgb2YgY29tcGFuaWVzIGFyZSBkaXNjbG9zaW5nIHBheSByYW5nZSBpbmZvcm1hdGlvbiBpbiBVLlMuIGxvY2F0aW9ucyB3aGVyZSBub3QgcmVxdWlyZWQgYnkgc3RhdGUgb3IgbG9jYWwgbGF3cy4gRm9yIHRoZSBzdGF0ZXMgdGhhdCBoYXZlIHBheSB0cmFuc3BhcmVuY3kgbGF3cyBzdWNoIGFzIENvbG9yYWRvIGFuZCBOZXcgWW9yaywgdGhlcmUgaGFzIGJlZW4gYSBkZWNsaW5lIGluIGpvYiBwb3N0aW5ncyBzaW5jZSB0aGUgbGF3IHdlbnQgaW50byBlZmZlY3QuIFNvbWUgZW1wbG95ZXJzIGNvbXBseSB3aXRoIHRoZSBuZXcgbGF3cyBieSBleHBhbmRpbmcgdGhlIHNhbGFyeSByYW5nZXMsIHNvbWV0aW1lcyB0byByaWRpY3Vsb3VzIGxlbmd0aHMuIFRoZXNlIHN0YXRpc3RpY3MgaGlnaGxpZ2h0IHRoZSBsYWNrIG9mIHBheSB0cmFuc3BhcmVuY3kgbm90IG9ubHkgaW4gdGhlIGZpZWxkIG9mIGRhdGEgc2NpZW5jZSwgYnV0IGFjcm9zcyBtdWx0aXBsZSBqb2IgbWFya2V0cy4gSm9iIHNlZWtlcnMgb2Z0ZW4gc3RydWdnbGUgdG8gZXN0aW1hdGUgc2FsYXJpZXMgZm9yIGRhdGEgc2NpZW5jZSBwb3NpdGlvbnMgZHVlIHRvIHRoZSBzY2FyY2l0eSBvZiByZWxpYWJsZSBpbmZvcm1hdGlvbi4NCg0KICAgIFRvIGFkZHJlc3MgdGhpcyBwcm9ibGVtLCBvdXIgcHJvamVjdCBhaW1zIHRvIGRldmVsb3AgYSBwcmVkaWN0aXZlIG1vZGVsIHRoYXQgZXN0aW1hdGVzIHRoZSBzYWxhcnkgZm9yIGRhdGEgc2NpZW5jZSBqb2JzLiBCeSBsZXZlcmFnaW5nIHB1YmxpY2x5IGF2YWlsYWJsZSBkYXRhIGFuZCBlbXBsb3lpbmcgbWFjaGluZSBsZWFybmluZyBhbGdvcml0aG1zLCB3ZSBzZWVrIHRvIHByb3ZpZGUgam9iIHNlZWtlcnMgYSBiZXR0ZXIgdW5kZXJzdGFuZGluZyBvZiBzYWxhcnkgZXhwZWN0YXRpb25zIHdpdGhpbiB0aGUgZGF0YSBzY2llbmNlIGpvYiBtYXJrZXQgYW5kIGVtcG93ZXIgdGhlbSB0byBuZWdvdGlhdGUgZmFpciBhbmQgY29tcGV0aXRpdmUgY29tcGVuc2F0aW9uIHBhY2thZ2VzLlwNCg0KMi4gICoqRGF0YSBTb3VyY2VzIGFuZCBEYXRhIHByZXBhcmF0aW9uKioNCiAqIEluc3RhbGwgcGFja2FnZXMgDQpgYGB7cn0NCiNpbnN0YWxsLnBhY2thZ2VzKCJycGFydC5wbG90IikNCiNpbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikNCiNpbnN0YWxsLnBhY2thZ2VzKCJlMTA3MSIpDQojIEluc3RhbGwgdGhlIHBsb3RseSBwYWNrYWdlDQojaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IikNCg0KYGBgDQoqIEltcG9ydCBkYXRhDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmRzX3NhbGFyaWVzIDwtIHJlYWQuY3N2KCJkc19zYWxhcmllcy5jc3YiKQ0KYGBgDQoqIERhdGEgZGVzY3JpcHRpb24NCmBgYHtyfQ0Kc3VtbWFyeShkc19zYWxhcmllcykNCg0KYGBgDQoNCg0KDQoqIFRoZSBmaXJzdCA1IHJvd3MgDQpgYGB7cn0NCmhlYWQoZHNfc2FsYXJpZXMsNSkNCmBgYA0KVGhpcyBkYXRhc2V0IGhhcyA2MDcgcm93cyBhbmQgMTIgY29sdW1ucw0KDQoNCldlIHdhbnQgdG8gZm9jdXMgb24gIlVTRCIgY3VycmVuY3kgc28gd2Uga2VlcCB0aGUgInNhbGFyeV9pbl91c2QiIGNvbHVtbiBhbmQgZHJvcCAic2FsYXJ5X2N1cnJlbmN5IiBhbmQgInNhbGFyeSIgY29sdW1uIGJ5IHVzaW5nIHN1YnNldCgpDQpgYGB7cn0NCmRzX3NhbGFyaWVzIDwtIHN1YnNldChkc19zYWxhcmllcywgc2VsZWN0ID0gLWMoWCAsIHNhbGFyeV9jdXJyZW5jeSwgc2FsYXJ5KSkNCmhlYWQoZHNfc2FsYXJpZXMsIDUpDQpgYGANCg0KKiBDaGVjayBmb3IgbnVsbCB2YWx1ZXMNCmBgYHtyfQ0KbnVtX251bGxfcm93cyA8LSBzdW0ocm93U3Vtcyhpcy5uYShkc19zYWxhcmllcykpID09IG5jb2woZHNfc2FsYXJpZXMpKQ0KcHJpbnQobnVtX251bGxfcm93cykNCmBgYA0KVGhlcmUgYXJlIG5vIG51bGwgdmFsdWVzDQoNCiogQ2hlY2sgZm9yIGR1cGxpY2F0ZSByb3dzDQpgYGB7cn0NCnJlcGVhdGVkX2VudHJpZXMgPC0gc3Vic2V0KGRzX3NhbGFyaWVzLCBkdXBsaWNhdGVkKGRzX3NhbGFyaWVzKSkNCnByaW50KHJlcGVhdGVkX2VudHJpZXMpDQpgYGANClRoZXJlIGFyZSA0MiBkdXBsaWNhdGUgcm93cw0KDQoqIFJlbW92ZSBkdXBsaWNhdGVzDQpgYGB7cn0NCiMgUmVtb3ZlIGR1cGxpY2F0ZSByb3dzDQpkZiA8LSBkc19zYWxhcmllc1shZHVwbGljYXRlZChkc19zYWxhcmllcyksIF0NCiMgY2hlY2sgYWdhaW4NCnJlcGVhdGVkX2VudHJpZXNfbmV3IDwtIHN1YnNldChkZiwgZHVwbGljYXRlZChkZikpDQpwcmludChyZXBlYXRlZF9lbnRyaWVzX25ldykNCmBgYA0KIyMjIFNhbGFyaWVzIGdyb3VwcyANCkFkZGluZyBuZXcgY29sdW1uIHRvIHNwbGl0IG91ciBzYWxhcmllcyBpbnRvIHRocmVlIGdyb3VwcyBMb3cgLCBIaWdoLCBNZWRpdW0uVGhlIGFwcHJvYWNoIGlzIHRvIHVzZSBQZXJjZW50aWxlcyBieSBEaXZpZGluZyB0aGUgZGF0YXNldCBiYXNlZCBvbiB0aGVtLiBIZW5jZSwgd2UgYXJlIGNsYXNzaWZ5aW5nIHNhbGFyaWVzIGJlbG93IHRoZSAyNXRoIHBlcmNlbnRpbGUgYXMgIkxvdyIsIHNhbGFyaWVzIGJldHdlZW4gdGhlIDI1dGggYW5kIDc1dGggcGVyY2VudGlsZSBhcyAiTWVkaXVtIiwgYW5kIHNhbGFyaWVzIGFib3ZlIHRoZSA3NXRoIHBlcmNlbnRpbGUgYXMgIkhpZ2giLg0KDQpgYGB7cn0NCiMgYWRkaW5nIG5ldyBjb2x1bW4gDQojIENhbGN1bGF0ZSB0aGUgcGVyY2VudGlsZXMNCnBlcmNlbnRpbGVzIDwtIHF1YW50aWxlKGRmJHNhbGFyeV9pbl91c2QsIHByb2JzID0gYygwLjI1LCAwLjc1KSkNCg0KIyBEZWZpbmUgdGhlIHRocmVzaG9sZHMNCmxvd190aHJlc2hvbGQgPC0gcGVyY2VudGlsZXNbMV0gICMgMjV0aCBwZXJjZW50aWxlDQpoaWdoX3RocmVzaG9sZCA8LSBwZXJjZW50aWxlc1syXSAgIyA3NXRoIHBlcmNlbnRpbGUNCg0KIyBDcmVhdGUgYSBuZXcgY29sdW1uIGJhc2VkIG9uIHBlcmNlbnRpbGVzDQpkZiRzYWxhcnlfY2xhc3NpZmljYXRpb24gPC0gaWZlbHNlKGRmJHNhbGFyeV9pbl91c2QgPCBsb3dfdGhyZXNob2xkLCAiTG93IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJHNhbGFyeV9pbl91c2QgPiBoaWdoX3RocmVzaG9sZCwgIkhpZ2giLCAiTWVkaXVtIikpDQoNCmBgYA0KDQoNCjMuICAqKkRhdGEgRXhwbG9yYXRpb24gYW5kIFZpc3VhbGl6YXRpb24qKg0KDQojIyMgVG9wIDEwIEpvYnMgaW4gdGhlIGRhdGFzZXQ6IA0KDQoNCg0KYGBge3J9DQojIEdldCB0b3AgMTAgam9iIHRpdGxlcyBhbmQgdGhlaXIgdmFsdWUgY291bnRzDQp0b3AxMF9qb2JfdGl0bGUgPC0gaGVhZChzb3J0KHRhYmxlKGRmJGpvYl90aXRsZSksIGRlY3JlYXNpbmcgPSBUUlVFKSwgMTApDQoNCnRvcDEwX2pvYl90aXRsZV9kZiA8LSBkYXRhLmZyYW1lKGpvYl90aXRsZSA9IG5hbWVzKHRvcDEwX2pvYl90aXRsZSksIGNvdW50ID0gYXMubnVtZXJpYyh0b3AxMF9qb2JfdGl0bGUpKQ0KdG9wMTBfam9iX3RpdGxlX2RmDQoNCmBgYA0KYGBge3J9DQojIExvYWQgdGhlIHJlcXVpcmVkIHBhY2thZ2VzDQpsaWJyYXJ5KHBsb3RseSkNCg0KIyBEZWZpbmUgY3VzdG9tIGNvbG9yIHBhbGV0dGUNCmN1c3RvbV9jb2xvcnMgPC0gYygiI0ZGNjM2MSIsICIjRkZBNjAwIiwgIiNGRkQ3MDAiLCAiI0ZGNzZCQyIsICIjNjlEMkU3IiwgIiM2QTA1NzIiLCAiI0ZGMzRCMyIsICIjMTE4QUIyIiwgIiNGRkZGOTkiLCAiI0ZGQzFDQyIpDQoNCiMgQ3JlYXRlIGJhciBwbG90DQpmaWcgPC0gcGxvdF9seShkYXRhID0gdG9wMTBfam9iX3RpdGxlX2RmLCB4ID0gfnJlb3JkZXIoam9iX3RpdGxlLCAtY291bnQpLCB5ID0gfmNvdW50LCB0eXBlID0gImJhciIsDQogICAgICAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gY3VzdG9tX2NvbG9ycyksIHRleHQgPSB+Y291bnQpICU+JQ0KICBsYXlvdXQodGl0bGUgPSAiVG9wIDEwIEpvYiBUaXRsZXMiLCB4YXhpcyA9IGxpc3QodGl0bGUgPSAiSm9iIFRpdGxlcyIpLCB5YXhpcyA9IGxpc3QodGl0bGUgPSAiQ291bnQiKSwNCiAgICAgICAgIGZvbnQgPSBsaXN0KHNpemUgPSAxNyksIHRlbXBsYXRlID0gInBsb3RseV9kYXJrIikNCg0KIyBBZGp1c3QgbGF5b3V0IHNldHRpbmdzIHRvIGF2b2lkIGxhYmVsIG92ZXJsYXANCmZpZyA8LSBmaWcgJT4lIGxheW91dCgNCiAgbWFyZ2luID0gbGlzdChiID0gMTUwKSwgICMgSW5jcmVhc2UgYm90dG9tIG1hcmdpbiB0byBwcm92aWRlIHNwYWNlIGZvciBsYWJlbHMNCiAgeGF4aXMgPSBsaXN0KA0KICAgIHRpY2thbmdsZSA9IDQ1LCAgIyBSb3RhdGUgeC1heGlzIHRpY2sgbGFiZWxzDQogICAgYXV0b21hcmdpbiA9IFRSVUUgICMgQXV0b21hdGljYWxseSBhZGp1c3QgbWFyZ2lucyB0byBhdm9pZCBvdmVybGFwDQogICkNCikNCg0KIyBEaXNwbGF5IHRoZSBwbG90DQpmaWcNCg0KDQpgYGANCg0KIyMjIEV4cGVyaWVuY2UgbGV2ZWwgY2F0ZWdvcmllczoNCk91ciBEYXRhc2V0IGhhcyA0IGRpZmZlcmVudCBleHBlcmllbmNlIGNhdGVnb3JpZXM6DQotIEVOOiBFbnRyeS1sZXZlbCAvIEp1bmlvcg0KLSBNSTogTWlkLWxldmVsIC8gSW50ZXJtZWRpYXRlDQotIFNFOiBTZW5pb3ItbGV2ZWwgLyBFeHBlcnQNCi0gRVg6IEV4ZWN1dGl2ZS1sZXZlbCAvIERpcmVjdG9yDQoNCmBgYHtyfQ0KIyBDcmVhdGUgYSBtYXBwaW5nIG9mIGNhdGVnb3J5IGFiYnJldmlhdGlvbnMgdG8gZnVsbCBuYW1lcw0KY2F0ZWdvcnlfbmFtZXNfZXhwZXJpZW5jZSA8LSBjKCJFTiIgPSAiRW50cnktbGV2ZWwiLA0KICAgICAgICAgICAgICAgICAgICAiTUkiID0gIk1pZC1sZXZlbCIsDQogICAgICAgICAgICAgICAgICAgICJTRSIgPSAiU2VuaW9yLWxldmVsIiwNCiAgICAgICAgICAgICAgICAgICAgIkVYIiA9ICJFeGVjdXRpdmUtbGV2ZWwiKQ0KDQojIEdldCB0aGUgc29ydGVkIGV4cGVyaWVuY2UgZGF0YQ0KZXhwZXJpZW5jZSA8LSBoZWFkKHNvcnQodGFibGUoZGYkZXhwZXJpZW5jZV9sZXZlbCksIGRlY3JlYXNpbmcgPSBUUlVFKSkNCg0KIyBSZXBsYWNlIHRoZSBjYXRlZ29yeSBuYW1lcyB3aXRoIGZ1bGwgZm9ybXMNCm5hbWVzKGV4cGVyaWVuY2UpIDwtIGNhdGVnb3J5X25hbWVzX2V4cGVyaWVuY2VbbmFtZXMoZXhwZXJpZW5jZSldDQoNCiMgQ2FsY3VsYXRlIHRoZSBwZXJjZW50YWdlIGZvciBlYWNoIGNhdGVnb3J5DQpwZXJjZW50YWdlcyA8LSByb3VuZCgxMDAgKiBleHBlcmllbmNlIC8gc3VtKGV4cGVyaWVuY2UpLCAyKQ0KDQojIERlZmluZSBhIGN1c3RvbSBjb2xvciBwYWxldHRlDQpjdXN0b21fY29sb3JzIDwtIGMoIiNGRkE5OTgiLCAiI0ZGNzZCQyIsICIjNjlEMkU3IiwgIiNGRkE2MDAiKQ0KDQojIENyZWF0ZSBhIHBpZSBjaGFydCB3aXRoIGN1dGUgYXBwZWFyYW5jZQ0KcGllKGV4cGVyaWVuY2UsIGxhYmVscyA9IHBhc3RlKG5hbWVzKGV4cGVyaWVuY2UpLCAiKCIsIHBlcmNlbnRhZ2VzLCAiJSkiKSwgY29sID0gY3VzdG9tX2NvbG9ycywgYm9yZGVyID0gIndoaXRlIiwgY2xvY2t3aXNlID0gVFJVRSwgaW5pdC5hbmdsZSA9IDkwKQ0KDQojIEFkZCBhIGxlZ2VuZCB3aXRoIGN1dGUgY29sb3JzDQpsZWdlbmQoInRvcHJpZ2h0IiwgbGVnZW5kID0gbmFtZXMoZXhwZXJpZW5jZSksIGZpbGwgPSBjdXN0b21fY29sb3JzLCBib3JkZXIgPSAid2hpdGUiLCBjZXggPSAwLjgpDQoNCiMgQWRkIGEgdGl0bGUgd2l0aCBhIGN1dGUgZm9udA0KdGl0bGUoIkV4cGVyaWVuY2UgRGlzdHJpYnV0aW9uIiwgZm9udC5tYWluID0gMSkNCg0KYGBgDQojIyMgQ29tcG5heSBzaXplIGRpc3RyaWJ1dGlvbiANCmBgYHtyfQ0KIyBDcmVhdGUgYSBtYXBwaW5nIG9mIGNhdGVnb3J5IGFiYnJldmlhdGlvbnMgdG8gZnVsbCBuYW1lcw0KY2F0ZWdvcnlfbmFtZXNfY29tcGFueSA8LSBjKCJNIiA9ICJNZWRpdW0iLA0KICAgICAgICAgICAgICAgICAgICAiTCIgPSAiTGFyZ2UiLA0KICAgICAgICAgICAgICAgICAgICAiUyIgPSAiU21hbGwiDQogICAgICAgICAgICAgICAgICAgKQ0KDQoNCiMgR2V0IHRoZSBzb3J0ZWQgY29tcGFueSBzaXplIGRhdGENCmNvbXBhbnlfc2l6ZSA8LSBoZWFkKHNvcnQodGFibGUoZGYkY29tcGFueV9zaXplKSwgZGVjcmVhc2luZyA9IFRSVUUpKQ0KDQojIFJlcGxhY2UgdGhlIGNhdGVnb3J5IG5hbWVzIHdpdGggZnVsbCBmb3Jtcw0KbmFtZXMoY29tcGFueV9zaXplKSA8LSBjYXRlZ29yeV9uYW1lc19jb21wYW55W25hbWVzKGNvbXBhbnlfc2l6ZSldDQoNCiMgU2V0IHRoZSBtYXhpbXVtIHZhbHVlIGZvciB0aGUgeS1heGlzDQptYXhfY291bnQgPC0gbWF4KGNvbXBhbnlfc2l6ZSkNCg0KIyBDcmVhdGUgYSBiYXIgcGxvdCB3aXRoIGFkanVzdGVkIHktYXhpcyBsaW1pdHMNCmJhcnBsb3QoY29tcGFueV9zaXplLCBjb2wgPSBjdXN0b21fY29sb3JzLCBtYWluID0gIkNvbXBhbnkgU2l6ZSBEaXN0cmlidXRpb24iLCB4bGFiID0gIkNvbXBhbnkgU2l6ZSIsIHlsYWIgPSAiQ291bnQiLCB5bGltID0gYygwLCBtYXhfY291bnQgKyAxMCkpDQoNCg0KYGBgDQojIyMgU2FsYXJpZXMgRGlzdHJpYnV0aW9uIA0KYGBge3J9DQojIFNldCB0aGUgc2NpcGVuIG9wdGlvbiB0byBhIGhpZ2ggdmFsdWUNCm9wdGlvbnMoc2NpcGVuID0gMTApDQoNCiMgQ3JlYXRlIGJveHBsb3Qgb2Ygc2FsYXJpZXMNCmJwIDwtIGJveHBsb3QoZGYkc2FsYXJ5X2luX3VzZCAvIDEwMDAsIA0KICAgICAgICBjb2wgPSAic2t5Ymx1ZSIsIA0KICAgICAgICBtYWluID0gIkJveHBsb3Qgb2YgU2FsYXJpZXMiLA0KICAgICAgICB5bGFiID0gIlNhbGFyeSBpbiBUaG91c2FuZHMgVVNEIiwNCiAgICAgICAgbm90Y2ggPSBUUlVFKQ0KDQpgYGANCiMjIyBTYWxhcmllcyBjbGFzc2lmaWNhdGlvbiBEaXN0cmlidXRpb24gDQpgYGB7cn0NCg0KDQojIEdldCB0aGUgc29ydGVkIHNhbGFyeSBjbGFzc2lmaWNhdGlvbiBkYXRhDQpzYWxhcnlfY2xhc3NpZmljYXRpb24gPC0gc29ydCh0YWJsZShkZiRzYWxhcnlfY2xhc3NpZmljYXRpb24pLCBkZWNyZWFzaW5nID0gVFJVRSkNCg0KDQpzYWxhcnlfY2xhc3NpZmljYXRpb25fZGYgPC0gZGF0YS5mcmFtZShzYWxhcnlfY2xhc3NpZmljYXRpb249IG5hbWVzKHNhbGFyeV9jbGFzc2lmaWNhdGlvbiApLCBjb3VudCA9IGFzLm51bWVyaWMoc2FsYXJ5X2NsYXNzaWZpY2F0aW9uICkpDQoNCmZpZyA8LSBwbG90X2x5KA0KICBkYXRhID0gc2FsYXJ5X2NsYXNzaWZpY2F0aW9uX2RmLA0KICB4ID0gfnJlb3JkZXIoc2FsYXJ5X2NsYXNzaWZpY2F0aW9uLCAtY291bnQpLA0KICB5ID0gfmNvdW50LA0KICB0eXBlID0gImJhciIsDQogIG1hcmtlciA9IGxpc3QoY29sb3IgPSBjdXN0b21fY29sb3JzKSwNCiAgdGV4dCA9IH5jb3VudCwNCiAgd2lkdGggPSA3MDAsDQogIGhlaWdodCA9IDQwMA0KKQ0KDQpmaWcgPC0gZmlnICU+JSBsYXlvdXQoDQogIHRpdGxlID0gIlNhbGFyeSBDbGFzc2lmaWNhdGlvbiBEaXN0cmlidXRpb24iLA0KICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiU2FsYXJ5IENsYXNzaWZpY2F0aW9uIiksDQogIHlheGlzID0gbGlzdCh0aXRsZSA9ICJDb3VudCIpLA0KICBmb250ID0gbGlzdChzaXplID0gMTcpLA0KICB0ZW1wbGF0ZSA9ICJnZ3Bsb3QyIg0KKQ0KDQpmaWcNCg0KDQoNCmBgYA0KYGBge3J9DQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgd2l0aCBjb3VudHMgb2YgZXhwZXJpZW5jZSBsZXZlbHMgYnkgc2FsYXJ5IGNsYXNzaWZpY2F0aW9uDQpleHBlcmllbmNlX3NhbGFyeSA8LSB0YWJsZShkZiRleHBlcmllbmNlX2xldmVsLCBkZiRzYWxhcnlfY2xhc3NpZmljYXRpb24pDQoNCiMgRGVmaW5lIGN1c3RvbSBjb2xvcnMgZm9yIGVhY2ggZXhwZXJpZW5jZSBsZXZlbA0KY3VzdG9tX2NvbG9ycyA8LSBjKCIjNjlEMkU3IiwgIiNGRkE2MDAiLCAiI0ZGNjM2MSIsICIjRkZENzAwIikNCg0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciB0aGUgcGxvdA0KcGxvdF9kYXRhIDwtIGRhdGEuZnJhbWUoRXhwZXJpZW5jZSA9IHJvd25hbWVzKGV4cGVyaWVuY2Vfc2FsYXJ5KSwgDQogICAgICAgICAgICAgICAgICAgICAgICBTYWxhcnlfQ2xhc3NpZmljYXRpb24gPSBjb2xuYW1lcyhleHBlcmllbmNlX3NhbGFyeSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgQ291bnQgPSBhcy52ZWN0b3IoZXhwZXJpZW5jZV9zYWxhcnkpKQ0KDQojIENvbnZlcnQgQ291bnQgY29sdW1uIHRvIG51bWVyaWMNCnBsb3RfZGF0YSRDb3VudCA8LSBhcy5udW1lcmljKHBsb3RfZGF0YSRDb3VudCkNCg0KIyBDcmVhdGUgdGhlIGJhciBwbG90DQpsaWJyYXJ5KHBsb3RseSkNCmZpZyA8LSBwbG90X2x5KGRhdGEgPSBwbG90X2RhdGEsIHggPSB+U2FsYXJ5X0NsYXNzaWZpY2F0aW9uLCB5ID0gfkNvdW50LCANCiAgICAgICAgICAgICAgIGNvbG9yID0gfkV4cGVyaWVuY2UsIGNvbG9ycyA9IGN1c3RvbV9jb2xvcnMsIHR5cGUgPSAiYmFyIikgJT4lDQogIGxheW91dCh0aXRsZSA9ICJFeHBlcmllbmNlIExldmVsIGJ5IFNhbGFyeSBDbGFzc2lmaWNhdGlvbiIsDQogICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiU2FsYXJ5IENsYXNzaWZpY2F0aW9uIiksDQogICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiQ291bnQiKSwNCiAgICAgICAgIGZvbnQgPSBsaXN0KHNpemUgPSAxNyksDQogICAgICAgICB0ZW1wbGF0ZSA9ICJwbG90bHlfZGFyayIpDQoNCmZpZw0KDQoNCmBgYA0KDQoNCg0KNC4gICoqTW9kZWxpbmcqKg0KDQoNCg0KICAgIGFcLiBMb2dlc3RpYyBSZWdyZXNzaW9uDQoNCiAgICBiXC4gUmFuZG9tIEZvcmVzdA0KDQogICAgY1wuIERlY2lzaW9uIFRyZWUNCg0KNS4gICoqRXZhbHVhdGlvbiBhbmQgUmVzdWx0cyoqDQoNCiAgICBhXC4gTGluZWFyIFJlZ3Jlc3Npb24NCg0KICAgIGJcLiBSYW5kb20gRm9yZXN0DQoNCiAgICBjXC4gRGVjaXNpb24gVHJlZQ0KDQo2LiAgKipNYWpvciBDaGFsbGVuZ2VzIGFuZCBTb2x1dGlvbnNcDQogICAgKioNCg0KICAgIC0gICBEYXRhIGlzIG5vdCB1cGRhdGVkDQoNCiAgICAtICAgRGF0YSBpcyBpbWJhbGFuY2VkDQoNCjcuICAqKkNvbmNsdXNpb24gYW5kIEZ1dHVyZSBXb3JrKioNCg0KOC4gICoqUmVmZXJlbmNlcyoqDQoNCiAgICBbVGhlIERhdGEgU2NpZW50aXN0IEpvYiBPdXRsb29rIGluIDIwMjMgXHwgMzY1IERhdGEgU2NpZW5jZV0oaHR0cHM6Ly8zNjVkYXRhc2NpZW5jZS5jb20vY2FyZWVyLWFkdmljZS9kYXRhLXNjaWVudGlzdC1qb2Itb3V0bG9vay8pDQoNCiAgICBbV2hpY2ggSW5kdXN0cnkgUGF5cyB0aGUgSGlnaGVzdCBEYXRhIFNjaWVudGlzdCBTYWxhcnk/IEhvdyBUbyBNYWtlIFRoZSBNb3N0IE1vbmV5IEFzIEEgRGF0YSBTY2llbnRpc3QgLSBaaXBwaWFdKGh0dHBzOi8vd3d3LnppcHBpYS5jb20vYWR2aWNlL2hpZ2hlc3QtcGF5aW5nLWRhdGEtc2NpZW50aXN0LWpvYnMvKQ0KDQogICAgW0J1cnRjaC1Xb3Jrcy1TdHVkeV9EUy1QQVAtMjAxOS5wZGYgKGJ1cnRjaHdvcmtzLmNvbSldKGh0dHBzOi8vd3d3LmJ1cnRjaHdvcmtzLmNvbS93cC1jb250ZW50L3VwbG9hZHMvMjAxOS8wNi9CdXJ0Y2gtV29ya3MtU3R1ZHlfRFMtUEFQLTIwMTkucGRmKQ0KDQogICAgW05ldyBWaXNpZXIgUmVwb3J0IFJldmVhbHMgNzklIG9mIEVtcGxveWVlcyBXYW50IFBheSBUcmFuc3BhcmVuY3kgKHBybmV3c3dpcmUuY29tKV0oaHR0cHM6Ly93d3cucHJuZXdzd2lyZS5jb20vbmV3cy1yZWxlYXNlcy9uZXctdmlzaWVyLXJlcG9ydC1yZXZlYWxzLTc5LW9mLWVtcGxveWVlcy13YW50LXBheS10cmFuc3BhcmVuY3ktMzAxNTI3MzA1Lmh0bWwpDQoNCiAgICBbTW9yZSBOQSBvcmdhbml6YXRpb25zIHBsYW4gdG8gZGlzY2xvc2UgcGF5IGluZm9ybWF0aW9uIC0gV1RXICh3dHdjby5jb20pXShodHRwczovL3d3dy53dHdjby5jb20vZW4tdXMvbmV3cy8yMDIyLzA5L21vcmUtbm9ydGgtYW1lcmljYW4tb3JnYW5pemF0aW9ucy1wbGFuLXRvLWRpc2Nsb3NlLXBheS1pbmZvcm1hdGlvbi1zdXJ2ZXktZmluZHMpDQoNCiAgICBbU3R1ZHk6IFBheSBUcmFuc3BhcmVuY3kgUmVkdWNlcyBSZWNydWl0aW5nIENvc3RzIChzaHJtLm9yZyldKGh0dHBzOi8vd3d3LnNocm0ub3JnL3Jlc291cmNlc2FuZHRvb2xzL2hyLXRvcGljcy90YWxlbnQtYWNxdWlzaXRpb24vcGFnZXMvcGF5LXRyYW5zcGFyZW5jeS1yZWR1Y2VzLXJlY3J1aXRpbmctY29zdHMuYXNweCk=